#ifndef ANY_HPP
#define ANY_HPP
#include <memory>
#include <typeindex>
#include <iostream>

/**
 * @brief The Any struct 转换成任何数据类型 auto? (^v^)
 * @author hzh 20231203
 */
struct Any
{
    // 默认构造函数，使用 nullptr 来初始化 m_ptr 表示空状态
    Any(void) : m_ptr(nullptr) , m_tpIndex(std::type_index(typeid(void))) {}
    Any(Any& that) : m_ptr(that.Clone()) , m_tpIndex(that.m_tpIndex) {}
    Any(Any&& that): m_ptr(std::move(that.m_ptr)) , m_tpIndex(that.m_tpIndex){}

    // 创建智能指针时，对于一般的类型，通过std::decay 来移除引用和cv符,从而获取原始类型
    /*class = typename std::enable_if<std::is_same<typename std::decay<U>::type,Any>::value,U>::type*/
    template<typename U>
    Any(U && value) :
        m_ptr(new Derived<typename std::decay<U>::type>(std::forward<U>(value))) ,
        m_tpIndex(std::type_index(typeid(typename std::decay<U>::type))){}

    bool IsNull() const
    {
        return !bool(m_ptr);
    }

    template<class U> bool Is() const
    {
        return (m_tpIndex == std::type_index(typeid (U)));
    }

    // 将Any 转换成实际类型
    template<class U>
    U& AnyCast() const
    {
        if (!Is<U>())
        {
            std::cout << "can't not cast " << typeid(U).name() << " to " << m_tpIndex.name() << std::endl;
            throw std::bad_cast();
        }
        auto derived = dynamic_cast<Derived<U>*> (m_ptr.get());
        return derived->m_value;
    }

    Any& operator=(const Any& a)
    {
        if (m_ptr == a.m_ptr)
            return *this;
        m_ptr = a.Clone();
        m_tpIndex = a.m_tpIndex;
        return *this;
    }

//    Any& operator=(Any that) noexcept {
//            swap(*this, that);
//            return *this;
//    }

//    friend void swap(Any& lhs, Any& rhs) noexcept {
//        using std::swap;
//        swap(lhs.m_ptr, rhs.m_ptr);
//        swap(lhs.m_tpIndex, rhs.m_tpIndex);
//    }
private:
    struct Base;
    typedef std::unique_ptr<Base> BasePtr;
    struct Base
    {
        virtual ~Base() {}
        virtual BasePtr Clone() const = 0;
    };

    template<typename T>
    struct Derived : Base
    {
        template<typename U>
        Derived(U &&value) : m_value(std::forward<U>(value)) {}
        BasePtr Clone() const
        {
            return BasePtr(new Derived<T>(m_value));
        }
        T m_value;
    };

    BasePtr Clone() const
    {
        if (m_ptr)
            return m_ptr->Clone();
        return nullptr;
    }
    BasePtr m_ptr;
    std::type_index m_tpIndex;
};

#endif // ANY_HPP
